/**
 * 
 */
package br.ufpe.cin.mac.middleware.autonomic.monitors;

import java.io.IOException;

import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
import jpcap.PacketReceiver;
import jpcap.packet.Packet;

/**
 * @author Osmany
 * @author Rafael Roque
 * 
 */
public class NetworkMonitor extends Monitor implements PacketReceiver {

	private byte net_index;

	private Long bytes;

	private long lastCheck;

	JpcapCaptor captor;

	/**
	 * 
	 */
	public NetworkMonitor() {
		super(NetworkMonitor.class.getCanonicalName());
		this.bytes = 0L;
		this.net_index = 2;
		this.lastCheck = System.currentTimeMillis();
		captor = null;
		startMonitor();
	}

	public void receivePacket(Packet packet) {
		synchronized (bytes) {
			this.bytes += packet.len;
		}

	}

	public float bytesPerSecond() {
		long cbytes;
		long cCheck;
		synchronized (bytes) {
			cbytes = this.bytes;
			this.bytes = 0L;
		}
		cCheck = System.currentTimeMillis();
		float ret = (float) cbytes / (float) (cCheck - lastCheck) * 1000;
		lastCheck = cCheck;

		return ret;
	}

	public long getReceivedPacket() {
		getCaptor().updateStat();
		return getCaptor().received_packets;
	}

	public long getDroppedPacket() {
		getCaptor().updateStat();
		return getCaptor().dropped_packets;
	}

	public float errorRatio() {
		int dropped_packets;
		int received_packets;
		JpcapCaptor captor = getCaptor();
		captor.updateStat();
		dropped_packets = captor.dropped_packets;
		received_packets = captor.received_packets;
		return ((float) dropped_packets / (dropped_packets + received_packets));
	}

	private JpcapCaptor getCaptor() {
		if (captor == null) {
			NetworkInterface[] devices = JpcapCaptor.getDeviceList();
			int index = net_index; // set index of the interface that you want
			// to open.
			try {
				captor = JpcapCaptor.openDevice(devices[index], 65535, false,
						20);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return captor;
	}

	private void startMonitor() {

		Thread t = new Thread() {

			public void run() {
				captor = getCaptor();
				while (true) {
					Packet packet = captor.getPacket();
					if (packet != null) {
						synchronized (bytes) {
							bytes += packet.len;
						}
					}
				}
			}
		};
		t.start();
	}

	public void stopMonitor() {
		captor.close();
	}

	@Override
	public float getMonitoredValue() {
		return bytesPerSecond() / 1024;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		NetworkMonitor mon = new NetworkMonitor();

		while (true) {
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			float mean = mon.getMonitoredValue();
			float kmean = mean / 1000;
			System.out.println("Throughput: " + kmean + " KB/s");
			System.out.println("Error Ratio: " + mon.errorRatio());
		}
	}
}
